﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Polly;
using Polly.Wrap;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace EMC.VISITOR.Core;

    public class ResilienceHttpClient : IHttpClient
    {
        private readonly HttpClient _httpClient;
        // 根据url origin去创建policy
        private readonly Func<string, IEnumerable<Policy>> _policyCreator;
        // 把policy 打包成组合policy wraper ,进行本地缓存
        private readonly ConcurrentDictionary<string, PolicyWrap> _policyWrappers;
        private IHttpContextAccessor _httpContextAccessor;
        public ResilienceHttpClient(string applicationName, Func<string, IEnumerable<Policy>> policyCreator, ILogger<ResilienceHttpClient> logger, IHttpContextAccessor httpContextAccessor)
        {
            // TracingHandler :zipKin4net 来追踪链路
            //_httpClient = new HttpClient(new TracingHandler(applicationName));
            _httpClient = new HttpClient();
            _policyWrappers = new ConcurrentDictionary<string, PolicyWrap>();
            _policyCreator = policyCreator;
            _httpContextAccessor = httpContextAccessor;
        }
        public async Task<string> PostAsync<T>(string url, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
        {
            Func<HttpRequestMessage> func = () => CreateHttpRequestMessage(HttpMethod.Post, url, item);
            var response = await DoPostAsync(HttpMethod.Post, url, func, authorizationToken, requestId, authorizationMethod);
            if (!response.IsSuccessStatusCode)
                return null;

            return await response.Content.ReadAsStringAsync();
        }

        public async Task<string> PostAsync(string url, Dictionary<string, string> form, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
        {
            Func<HttpRequestMessage> func = () => CreateHttpRequestMessage(HttpMethod.Post, url, form);
            var response = await DoPostAsync(HttpMethod.Post, url, func, authorizationToken, requestId, authorizationMethod);
            if (!response.IsSuccessStatusCode)
                return null;

            return await response.Content.ReadAsStringAsync();

        }

        private Task<HttpResponseMessage> DoPostAsync(HttpMethod method, string url, Func<HttpRequestMessage> requestMessageFunction, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
        {
            if (method != HttpMethod.Post && method != HttpMethod.Put)
            {
                throw new ArgumentException("value must be either post or put.", nameof(method));
            }
            var ogigin = GetOriginFromUri(url);
            return HttpInvoker(ogigin, async () =>
            {
                HttpRequestMessage requestMessage = requestMessageFunction();
                SetAuthorizationHeader(requestMessage);
                if (authorizationToken != null)
                {
                    requestMessage.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(authorizationMethod, authorizationToken);
                }

                if (requestId != null)
                {
                    requestMessage.Headers.Add("x-requestid", requestId);
                }
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                var response = await _httpClient.SendAsync(requestMessage);

                if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
                {
                    throw new HttpRequestException();
                }
                return response;
            });
        }

        private HttpRequestMessage CreateHttpRequestMessage<T>(HttpMethod method, string url, T item)
        {
            return new HttpRequestMessage(method, url) { Content = new StringContent(JsonConvert.SerializeObject(item), Encoding.UTF8, "application/json") };
        }
        private HttpRequestMessage CreateHttpRequestMessage(HttpMethod method, string url, Dictionary<string, string> form)
        {
            return new HttpRequestMessage(method, url) { Content = new FormUrlEncodedContent(form) };
        }

        private async Task<T> HttpInvoker<T>(string origin, Func<Task<T>> action)
        {
            //var normalizedOrigin = NormalizeOrigin(origin);
            //if (!_policyWrappers.TryGetValue(normalizedOrigin, out PolicyWrap Wrap))
            //{
            //    var ttt = _policyCreator(normalizedOrigin).ToArray();
            //    Wrap = Policy.WrapAsync(ttt);
            //    _policyWrappers.TryAdd(normalizedOrigin, Wrap);
            //}
            //return await Wrap.ExecuteAsync(action, new Context(normalizedOrigin));

            return await action();
        }
        private static string GetOriginFromUri(string uri)
        {
            var url = new Uri(uri);
            var origin = $"{url.Scheme}://{url.DnsSafeHost}:{url.Port}";
            return origin;
        }
        private void SetAuthorizationHeader(HttpRequestMessage requestMessage)
        {
            if (_httpContextAccessor.HttpContext == null)
                return;
            var authorizationHeader = _httpContextAccessor.HttpContext.Request.Headers["Authorization"];
            if (!string.IsNullOrEmpty(authorizationHeader))
            {
                requestMessage.Headers.Add("Authorization", new List<string>() { authorizationHeader });
            }
        }
        private static string NormalizeOrigin(string origin)
        {
            return origin?.Trim().ToLower();
        }

        public Task<string> GetStringAsync(string url, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            var origin = GetOriginFromUri(url);
            return HttpInvoker(origin, async () =>
            {
                var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
                SetAuthorizationHeader(requestMessage);
                if (authorizationToken != null)
                {
                    requestMessage.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(authorizationMethod, authorizationToken);
                }
                var response = await _httpClient.SendAsync(requestMessage);
                if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
                {
                    throw new HttpRequestException();
                }
                if (!response.IsSuccessStatusCode)
                    return null;

                return await response.Content.ReadAsStringAsync();
                //return response;
            });
        }

        public Task<string> DeleteAsync(string url, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
        {
            throw new NotImplementedException();
        }

        public Task<HttpResponseMessage> PutAsync<T>(string url, T item, string authorizationToken = null, string requestId = null, string authorizationMethod = "Bearer")
        {
            Func<HttpRequestMessage> func = () => CreateHttpRequestMessage(HttpMethod.Post, url, item);
            return DoPostAsync(HttpMethod.Put, url, func, authorizationToken, requestId, authorizationMethod);
        }

        /// <summary>
        /// 向webapi发送请求执行导入操作
        /// </summary>
        /// <param name="token">身份验证token</param>
        /// <param name="reauestUrl">api请求完整路径</param>
        /// <param name="bytes">文件byte[]</param>
        /// <param name="fileName">文件名称</param>
        /// <returns></returns>
        public async Task<ResultJsonInfo<T>> PostSingleImage<T>(string requestUrl, byte[] bmpBytes,  string fileName)
        {
            var result = new ResultJsonInfo<T>(false);
            using (var httpClient = new HttpClient())
            {
                List<ByteArrayContent> byteArrayContents = new List<ByteArrayContent>();

                var fileContent = new ByteArrayContent(bmpBytes);//填充图片文件二进制字节
                fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
                fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
                {
                    Name = "file",
                    FileName = fileName,
                };
                byteArrayContents.Add(fileContent);

                var content = new MultipartFormDataContent();
                //将ByteArrayContent集合加入到MultipartFormDataContent中
                foreach (var byteArrayContent in byteArrayContents)
                {
                    content.Add(byteArrayContent);
                }

                try
                {
                    var res = await httpClient.PostAsync(requestUrl, content);//post请求
                    var readString = await res.Content.ReadAsStringAsync();
                    return Newtonsoft.Json.JsonConvert.DeserializeObject<ResultJsonInfo<T>>(readString);
                }
                catch (Exception ex)
                {
                    result.Fail("上传单文件错误");
                    return result;
                }
            }

           }

        /// <summary>
        /// Http Post 可传文件参数
        /// </summary>
        /// <param name="url"></param>
        /// <param name="dic">字符串 字典数据</param>
        /// <param name="dicFile">文件 字典数据</param>
        /// <returns></returns>
        public async Task<ResultJsonInfo<T>> PostFiles<T>(string url, Dictionary<string, string> dic,string requestname,  Dictionary<string, byte[]> dicFile)
        {
            var result = new ResultJsonInfo<T>(false);
            try
            {
                Uri uri = new Uri(url);

                var httpclientHandler = new HttpClientHandler();
                httpclientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true;

                HttpClient client = new HttpClient(httpclientHandler);
                var form = new MultipartFormDataContent();
                string boundary = string.Format("--{0}", DateTime.Now.Ticks.ToString("x"));
                form.Headers.Add("ContentType", $"multipart/form-data, boundary={boundary}");
                if (dic != null)
                {
                    foreach (var key in dic.Keys)
                    {
                        form.Add(new StringContent(dic[key].ToString()), key);
                    }
                }

                if (dicFile != null)
                {
                    foreach (var file in dicFile)
                    {
                        var fileContent = new ByteArrayContent(file.Value);
                        fileContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
                        form.Add(fileContent, name: requestname, fileName: file.Key);
                    }
                    //foreach (var key in dicFile.Keys)
                    //{
                    //    var fileContent = new ByteArrayContent(dicFile[key].Value);
                    //    fileContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
                    //    form.Add(fileContent, name: key, fileName: dicFile[key].Key);
                    //}
                }
                HttpResponseMessage response = await client.PostAsync(url, form);
                var readString = await response.Content.ReadAsStringAsync();
                result = Newtonsoft.Json.JsonConvert.DeserializeObject<ResultJsonInfo<T>>(readString);
                return result;
            }
            catch (Exception ex)
            {
                result.Fail("上传单多文件错误");
                return result;
            }
        }


    }

     


